//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
using OpenLS.Core;
using OpenLS.Core.Serialization;

namespace OpenLS.Spreadsheet
{
    /// <summary>
    /// Represents the style of a cell. 
    /// </summary>
    public class CellStyle : INotifyPropertyChanged, IOfficeXmlSerializable
    {
        internal enum BuiltInStyleId
        {
            Normal = 0,
            Percent20_Accent1 = 30,
            Percent20_Accent2 = 34,
            Percent20_Accent3 = 38,
            Percent20_Accent4 = 42,
            Percent20_Accent5 = 46,
            Percent20_Accent6 = 50,
            Percent40_Accent1 = 31,
            Percent40_Accent2 = 35,
            Percent40_Accent3 = 39,
            Percent40_Accent4 = 43,
            Percent40_Accent5 = 47,
            Percent40_Accent6 = 51,
            Percent60_Accent1 = 32,
            Percent60_Accent2 = 36,
            Percent60_Accent3 = 40,
            Percent60_Accent4 = 44,
            Percent60_Accent5 = 48,
            Percent60_Accent6 = 52,
            Accent1 = 29,
            Accent2 = 33,
            Accent3 = 37,
            Accent4 = 41,
            Accent5 = 45,
            Accent6 = 49,
            Bad = 27,
            Calculation = 22,
            CheckCell = 23,
            Comma = 3,
            Comma0 = 6,
            Currency = 4,
            Currency0 = 7,
            ExplanatoryText = 53,
            Good = 26,
            Heading1 = 16,
            Heading2 = 17,
            Heading3 = 18,
            Heading4 = 19,
            Input = 20,
            LinkedCell = 24,
            Neutral = 28,
            Note = 10,
            Output = 21,
            Percent = 5,
            Title = 15,
            Total = 25,
            WarningText = 11,
        }
        public override bool Equals(object obj)
        {
            if (obj == this)
                return true;
            if (obj is CellStyle)
                return EqualsCellStyle((CellStyle) obj);
            return base.Equals(obj);
        }
        static string GetBuiltInNameFromId (BuiltInStyleId id)
        {
            switch (id)
            {
                    case BuiltInStyleId.Normal: return "Normal";
case BuiltInStyleId.Percent20_Accent1: return "20% - Accent1";
case BuiltInStyleId.Percent20_Accent2: return "20% - Accent2";
case BuiltInStyleId.Percent20_Accent3: return "20% - Accent3";
case BuiltInStyleId.Percent20_Accent4: return "20% - Accent4";
case BuiltInStyleId.Percent20_Accent5: return "20% - Accent5";
case BuiltInStyleId.Percent20_Accent6: return "20% - Accent6";
case BuiltInStyleId.Percent40_Accent1: return "40% - Accent1";
case BuiltInStyleId.Percent40_Accent2: return "40% - Accent2";
case BuiltInStyleId.Percent40_Accent3: return "40% - Accent3";
case BuiltInStyleId.Percent40_Accent4: return "40% - Accent4";
case BuiltInStyleId.Percent40_Accent5: return "40% - Accent5";
case BuiltInStyleId.Percent40_Accent6: return "40% - Accent6";
case BuiltInStyleId.Percent60_Accent1: return "60% - Accent1";
case BuiltInStyleId.Percent60_Accent2: return "60% - Accent2";
case BuiltInStyleId.Percent60_Accent3: return "60% - Accent3";
case BuiltInStyleId.Percent60_Accent4: return "60% - Accent4";
case BuiltInStyleId.Percent60_Accent5: return "60% - Accent5";
case BuiltInStyleId.Percent60_Accent6: return "60% - Accent6";
case BuiltInStyleId.Accent1: return "Accent1";
case BuiltInStyleId.Accent2: return "Accent2";
case BuiltInStyleId.Accent3: return "Accent3";
case BuiltInStyleId.Accent4: return "Accent4";
case BuiltInStyleId.Accent5: return "Accent5";
case BuiltInStyleId.Accent6: return "Accent6";
case BuiltInStyleId.Bad: return "Bad";
case BuiltInStyleId.Calculation: return "Calculation";
case BuiltInStyleId.CheckCell: return "Check Cell";
case BuiltInStyleId.Comma: return "Comma";
case BuiltInStyleId.Comma0: return "Comma [0]";
case BuiltInStyleId.Currency: return "Currency";
case BuiltInStyleId.Currency0: return "Currency [0]";
case BuiltInStyleId.ExplanatoryText: return "Explanatory Text";
case BuiltInStyleId.Good: return "Good";
case BuiltInStyleId.Heading1: return "Heading 1";
case BuiltInStyleId.Heading2: return "Heading 2";
case BuiltInStyleId.Heading3: return "Heading 3";
case BuiltInStyleId.Heading4: return "Heading 4";
case BuiltInStyleId.Input: return "Input";
case BuiltInStyleId.LinkedCell: return "Linked Cell";
case BuiltInStyleId.Neutral: return "Neutral";
case BuiltInStyleId.Note: return "Note";
case BuiltInStyleId.Output: return "Output";
case BuiltInStyleId.Percent: return "Percent";
case BuiltInStyleId.Title: return "Title";
case BuiltInStyleId.Total: return "Total";
case BuiltInStyleId.WarningText: return "Warning Text";
            }
            return "No name";
        }

        private bool EqualsCellStyle(CellStyle other)
        {
            Contract.Assert(other != null);
            if (Name != other.Name)
                return false;
            if (_builtinId != other._builtinId)
                return false;
            if (Record == null && other.Record != null)
                return false;
            if (Record != null)
                return Record.EqualsRecord(other.Record);
            Contract.Assert(other.Record == null);
            return true;
        }

        public CellStyle()
        {
            Record = new StyleFormattingRecord();
        }
        public CellStyle(string name): this()
        {
            this.name = name;
        }

        internal void ReadXml(ReadContext context, List<StyleFormattingRecord> cellStyleRecords)
        {
            using (ReadContext c = context.Read("cellStyle"))
            {
                Name = c.GetOptionalString("name");
                //\\string xfId = GetOptionalString["xfId"];
                Record = cellStyleRecords[c.GetInteger("xfId")];
            }
        }

        private StyleFormattingRecord _record;
        internal StyleFormattingRecord Record
        {
            get
            {
                Contract.Ensures(Contract.Result<StyleFormattingRecord>() != null);
                Contract.Ensures(Contract.Result<StyleFormattingRecord>().Style == this);
                return _record;
            }
            set
            {
                Contract.Requires(value != null);
                Contract.Requires(value.Style  == null);
                Contract.Ensures(Record == value);
                _record = value;
                _record.Style = this;

            }
        }

        public SpreadsheetColor Foreground
        {
            get { return Record.Foreground; }
            set
            {
                Record.Foreground = value;
            }
        }
        public double FontSize
        {
            get { return Record.FontSize; }
            //\\set { Record.FontSize = value; }
        }
        public Borders Borders
        {
            get {
                return Record.Borders;
            }
        }
        public FontWeight FontWeight
        {
            get
            {
                return Record.FontWeight;
            }
        }
        public Format Format
        {
            get
            {
                return Record.Format;
            }
        }
	
       /* public ColorReference FontColor
        {
            get
            {
                return Record.FontColor;
            }
            set
            {
                Record.FontColor = value;
            }
        }*/
       public Fill Background
        {
            get { return Record.Background; }
            set
            {
                Record.Background = value;
            }
        }
       /* public Fill Fill
        {
            get
            {
                return Record.Background;
            }
            set
            {
                Record.Background = value;
            }
        }*/
        public FontStyle FontStyle { get { return Record.FontStyle; } }
        public FontFamily FontFamily { get { return Record.FontFamily; } }//\\
	
        private string name;

        public string Name
        {
            get
            {
                if (name != null)
                    return name;
                if (this._builtinId != null)
                    return GetBuiltInNameFromId((BuiltInStyleId) _builtinId.Value);
                // Contract.Assert(false);
                return "NONE";
            }
            set { name = value; NotifyPropertyChanged("Name"); }
        }
        private byte? _builtinId;
        internal byte? BuiltInId
        {
            get { return _builtinId; }
        }
        internal void SetBuiltInId(byte id, Workbook owner)
        {
            this._builtinId = id;
            this._owner = owner;
            NotifyPropertyChanged("Name");
        }

	
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        void NotifyPropertyChanged(string propertyName)
        {
            Contract.Requires(GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null);
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

        void IOfficeXmlSerializable.ReadXml(ReadContext context)
        {
            List<StyleFormattingRecord> cellStyleRecords = context.GetData<List<StyleFormattingRecord>>();
            Contract.Assert(cellStyleRecords != null);
            using (ReadContext c = context.Read("cellStyle"))
            {
                Name = c.GetOptionalString("name");
                //\\string xfId = GetOptionalString["xfId"];
                Record = cellStyleRecords[c.GetInteger("xfId")];
                int? i = c.GetOptionalInteger("builtinId");
                this._owner = c.GetData<Workbook>();
                if (i != null)
                {
                    SetBuiltInId((byte) i.Value, _owner);
                    _owner.StyleSheet.AddBuiltInStyle(this);
                }

            }
        }

        private Workbook _owner;
        public Workbook Owner { get { return _owner; } }

        internal bool IsBuiltIn
        {
            get
            {
                Contract.Ensures(Contract.Result<bool>() == (this._builtinId != null));
                return _builtinId != null;
            }
        }

        void IOfficeXmlSerializable.WriteXml(WriteContext context)
        {
            using (var c = context.Write("cellStyle"))
            {
                c.SetString("name", Name);
                c.SetOptionalInteger("builtinId", this._builtinId);
                c.SetInteger("xfId", context.GetData<Dictionary<FormattingRecord, int>>()[this.Record]);
            }
        }

#if DEBUG
        internal bool Accepts(Workbook workbook)
        {
            Contract.Assert(workbook != null);
            return this._owner == null || _owner == workbook;
        }
#endif

        public bool SameName(CellStyle style)
        {
            Contract.Requires(style != null);
            if (style.IsBuiltIn != this.IsBuiltIn)
                return false;
            if (style.IsBuiltIn)
                return style.BuiltInId == this.BuiltInId;
            return style.Name == this.Name;
        }
    }
}
